package org.lgiavedoni.android.franq.core.position;

import org.lgiavedoni.android.franq.core.Context;
import org.lgiavedoni.android.franq.core.place.PlaceManager;
import org.lgiavedoni.android.franq.core.position.dao.PositionDAO;
import org.lgiavedoni.android.franq.service.config.ConfigService;
import org.lgiavedoni.android.franq.service.config.ConfigService.ConfigKey;
import org.lgiavedoni.android.franq.service.log.Logger;
import org.lgiavedoni.android.franq.service.phone.location.LocationService;
import org.lgiavedoni.android.franq.util.date.DateUtil;
import org.lgiavedoni.android.franq.util.phone.wifi.WifiManager;
import org.lgiavedoni.android.franq.util.place.PlaceUtil;
import org.lgiavedoni.android.franq.util.thread.ThreadUtil;

import com.google.inject.Singleton;

@Singleton
public class PositionManager {

	public static final PositionManager inst = new PositionManager();
	private Position currentPosition = null;
	private Thread thread;

	private final WifiManager wifiManager;

	private PositionManager() {
		wifiManager = (WifiManager) Context.getResource(WifiManager.class);
	}

	public synchronized void tryToUpdatePosition() {
		if (thread != null && thread.isAlive())
			return;
		thread = new UpdatePosition();
		thread.start();
	}

	private class UpdatePosition extends Thread {

		@Override
		public void run() {
			try {
				setName("PositionManager.tryToUpdatePosition");
				double average = 1.05;// 5%
				boolean doubleCheck = false;
				// Wait after a event
				// ThreadUtil.sleep(ConfigService.inst.getValueAsLong(ConfigKey.POSITION_WAITE_BEFORE_CHECK));
				while (true) {
					// Get new position
					Position position = LocationService.inst.getLocation();
					// Position position = new
					// Position(wifiManager.listWifiNetworksBSSID());
					if (position != null && !position.isUnknow()) {
						// Is the same position?
						if (!PlaceUtil.areTheSamePlace(currentPosition, position)) {
							// New position
							currentPosition = position;
							// Add Position
							PositionDAO.inst.add(position);
						}

						// Is the same place?
						if (!doubleCheck && PlaceUtil.areTheSamePlace(PlaceManager.inst.getCurrentPlace(), position)) {
							// So maybe we need to wait some minutes
							ThreadUtil.sleep(ConfigService.inst.getValueAsLong(ConfigKey.POSITION_SAME_NEW_EVENT_SLEEP));
							// this only apply one time
							doubleCheck = true;
							continue;
						}

						// Check if is a new place
						if (PlaceManager.inst.tryToUpdatePlace(position)) {
							/**
							 * Ok, we have a new place. We are done We don't
							 * need to update the place in the next two minutes
							 */
							// ThreadUtil.sleepMinutes(2);
							break;
						} else {
							// Mmm, we still don't have a new place
							// Wait and try again
							double time = ConfigService.inst.getValueAsLong(ConfigKey.PLACE_MIN_STAY_TIME);
							time = time * average;
							average += 0.01;// + 1%

							// Never more than 30 minutes
							if (time > DateUtil.getMillisecondsOfMins(30)) {
								time = DateUtil.getMillisecondsOfMins(30);
							}
							ThreadUtil.sleep((long) time);
						}
					} else {
						// Position undefined, try again
						if (currentPosition != null) {
							currentPosition = null;
							PlaceManager.inst.tryToUpdatePlace(position);
						}
						ThreadUtil.sleep(ConfigService.inst.getValueAsLong(ConfigKey.POSITION_UNDEFINED_WAIT));
					}
				}
			} catch (Exception ex) {
				Logger.inst.error(ex);
			}

		}
	}

	public Position getCurrentPosition() {
		return currentPosition;
	}

}
